﻿// 0913train02.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <iomanip>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <limits>

using namespace std;

/*
 输入N个互不相同的二维整数坐标，求这N个坐标可以构成的正方形数量。[内积为零的的两个向量垂直]

输入描述
第一行输入为N，N代表坐标数量，N为正整数。N <= 100
之后的 N 行输入为坐标x y以空格分隔，x，y为整数，-10 <= x, y <= 10

输出描述
输出可以构成的正方形数量。

4
0 0
1 2
3 1
2 -1

四个点距离相等，构成正方形

a+b=x2-x1 a-b=y2-y1 a=(x2-x1)+(y2-y1)/2 b=(x2-x1)-(y2-y1)/2
 */
class Solution01
{
public:
    string vec2str(vector<double>& pos_vec)
    {
        stringstream str_sstream;
        str_sstream << pos_vec[0] << ',' << pos_vec[1];

        return str_sstream.str();
        //vec2str
    }

    vector<string>compute(vector<double>&pos_1, vector<double>& pos_2)
    {
        double x_1 = pos_1[0], y_1 = pos_1[1];
        double x_2 = pos_2[0], y_2 = pos_2[1];

        double a = ((x_2 - x_1) + (y_2 - y_1)) / 2;
        double b = ((x_2 - x_1) - (y_2 - y_1)) / 2;

        double x_3 = x_1 + b, y_3 = y_1 + a;
        double x_4 = x_1 + a, y_4 = y_1 - b;

        vector<string>result;
        vector<double>pos_3_v = { x_3, y_3 };
        string pos_3_str = vec2str(pos_3_v);
        result.push_back(pos_3_str);

        vector<double>pos_4_v = { x_4, y_4 };
        string pos_4_str = vec2str(pos_4_v);
        result.push_back(pos_4_str);
        return result;
    }
    Solution01(vector<vector<double>>&pos_vec)
    {
        int pos_size = pos_vec.size();
        if (pos_size<4)
        {
            cout << 0;
            return;
        }

        unordered_map<string, vector<string>>square_map;

        //暴力穷举2个点，塞进length_map
        //扫一遍square_map，寻找这两个点
        for (int i=0; i<pos_vec.size(); i++)
        {
            for (int next=i+1; next<pos_vec.size(); next++)
            {
                string pos_1_str = vec2str(pos_vec[i]);
                string pos_2_str = vec2str(pos_vec[next]);
                string key = pos_1_str + ' ' + pos_2_str;

                vector<string>other_point = compute(pos_vec[i], pos_vec[next]);
            	square_map[key] = other_point;
            }

            string point_str = vec2str(pos_vec[i]);
            total_point.insert(point_str);
        }

        int result = 0;
        for (auto&map_item:square_map)
        {
            bool is_find = true;
            for (auto&search_p:map_item.second)
            {
                if (total_point.count(search_p) == 0)
                    is_find = false;
            }
            if (is_find)
            {
                result += 1;
            }
        }
        cout << result/2;
        //Solution01
    }
private:
    unordered_set<string>total_point;
};


/*
 给定一个由多个命令字组成的命令字符串； 
1. 字符串长度小于等于127字节，只包含大小写字母，数字，下划线和偶数个双引号 
2. 命令字之间以一个或多个下划线_进行分割 
3. 可以通过两个双引号""来标识包含下划线_的命令字或空命令字（仅包含两个双引号的命令字）
双引号不会在命令字内部出现 

请对指定索引的敏感字段进行加密，替换为******（6 个*）
并删除命令字前后多余的下划线_
如果无法找到指定索引的命令字，输出字符串ERROR

输入描述
输入为两行 第一行为命令字索引 K（从0开始） 第二行为命令字符串S

输出描述
输出处理后的命令字符串 如果无法找到指定索引的命令字，输出字符串ERROR

输入
1
password_a12345678_timeout_100
输出
password_******_timeout_100
 */
class Solution02
{
public:
    Solution02(string& origin_str, int target_i)
    {
        //并删除命令字前后多余的下划线_
        string exec_str = origin_str;
        while (exec_str[0] == '_')
        {
            exec_str = exec_str.substr(1, exec_str.size() - 1);
        }
        while (exec_str[exec_str.size() - 1] == '_')
        {
            exec_str = exec_str.substr(0, exec_str.size() - 1);
        }

        vector<string>str_vec;
        bool allow_ch = false;
        string curr_str;
        int count_split = 0;
        for (int i = 0; i < exec_str.size(); i++)
        {
            //只包含大小写字母，数字，下划线和偶数个双引号
            char curr_char = exec_str[i];
            if (curr_char == '_')
            {
                if (allow_ch)
                {
                    curr_str += curr_char;
                }
                else
                {
                    str_vec.push_back(curr_str);
                    curr_str = "";
                }
            }
            else if (curr_char == '"')
            {
                count_split += 1;
                if (count_split % 2 != 0)
                {
                    //奇数
                    allow_ch = true;
                }
                else
                {
                    allow_ch = false;
                }
                curr_str += curr_char;
            }
            else
            {
                //数字，字母
                curr_str += curr_char;
            }

            //for
        }
        if (!curr_str.empty())
        {
            str_vec.push_back(curr_str);
        }

        if (target_i>=str_vec.size())
        {
            cout << "ERROR";
            return;
        }

        string result;
        for (int i=0; i<str_vec.size(); i++)
        {
	        if (i==target_i)
	        {
                result += "******";
	        }
            else
            {
                result += str_vec[i];
            }
            if (i!=str_vec.size()-1)
            {
                result += '_';
            }
        }

        cout << result;
        //Solution02
    }
};


/*
 每个数字对应多个字母，对应关系如下：
0：a,b,c
1：d,e,f
2：g,h,i
3：j,k,l
4：m,n,o
5：p,q,r
6：s,t
7：u,v
8：w,x
9：y,z
输入一串数字后，通过数字和字母的对应关系可以得到多个字母字符串
（要求按照数字的顺序组合字母字符串）;
屏蔽字符： 屏蔽字符中的所有字母不能同时在输出的字符串出现，
如屏蔽字符时 abc，则要求字符串中不能同时出现 a，b，c，
但是允许同时出现 a，b；a，c；b，c 等。
给定一个数字字符串和一个屏蔽字符串，
输出所有可能的字符组合；
例如输入数字字符串 78 和屏蔽字符串 ux，
输出结果为 uw，vw，vx；数字字符串 78，可以得到如下字符串：
uw，ux，vw，vx；由于 ux 是屏蔽字符串，因此排除 ux，最终的输出时 uw，vw，vx；

输入描述
第一行输入为一串数字字符串，数字字符串中的数字不允许重复，数字字符串的长度大于 0，小于等于 5；
第二行输入是屏蔽字符，屏蔽字符的长度一定小于数字字符串的长度，屏蔽字符串中字符不会重复。

输出描述
输出可能的字符串组合
注：字符串之间使用逗号隔开，最后一个字符串后携带逗号

输入
78
ux
输出
uw,vw,vx,
 */
class Solution03
{
public:
    void initData()
    {
/*
0：a,b,c
1：d,e,f
2：g,h,i
3：j,k,l
4：m,n,o
5：p,q,r
6：s,t
7：u,v
8：w,x
9：y,z
*/
        vector<string>combine_vec = {
        	"a,b,c","d,e,f","g,h,i","j,k,l",
			"m,n,o","p,q,r","s,t","u,v","w,x","y,z"
        };

        for (int i=0; i<combine_vec.size();i++)
        {
            string curr_str = combine_vec[i];
            stringstream combine_sstream(curr_str);
            string token;
            vector<char>ch_vec;
            while (getline(combine_sstream,token,','))
            {
                ch_vec.push_back(token[0]);
            }
            combine_map[i] = ch_vec;
        }

        //initData
    }
    void backTrack(string&num_str, int index)
    {
        //屏蔽字符中的所有字母不能同时在输出的字符串出现
        if (track.size()==num_str.size())
        {
            bool is_verify = false;
            for (auto& exclu_ch : exclu_set)
            {
                if (track_set.count(exclu_ch) == 0)
                {
                    is_verify = true;
                    break;
                }
            }
            if (is_verify)
            {
                string res;
                for (auto&ch:track)
                {
                    res += ch;
                }
                result.push_back(res);
            }
            return;
        }

        if (index == num_str.size()) return;
        int level = num_str[index] - '0';

        for (auto&curr_ch:combine_map[level])
        {
            //做选择
            track.push_back(curr_ch);
            track_set.insert(curr_ch);
            //回溯
            backTrack(num_str, index + 1);
            //撤销选择
            track.pop_back();
            track_set.erase(curr_ch);
        }

        //backTrack
    }

    Solution03(string&num_str, string&exclu)
    {
        initData();
        for (auto&ch:exclu)
        {
            exclu_set.insert(ch);
        }

        backTrack(num_str, 0);

        for (auto&str:result)
        {
            cout << str << ',';
        }
	    //Solution03
    }
private:
    vector<char>track;
    vector<string>result;
    unordered_set<char>track_set;
    unordered_set<char>exclu_set;
    unordered_map<int, vector<char>>combine_map;
};

int main()
{
	{
/*
4
0 0
1 2
3 1
2 -1
*/
        vector<vector<double>>pos_vec;
        int v_size;
        cin >> v_size;

        for (int i=0; i<v_size; i++)
        {
            vector<double>curr_pos(2);
            cin >> curr_pos[0] >> curr_pos[1];
            pos_vec.push_back(curr_pos);
        }
        Solution01 solu(pos_vec);

        //vector<vector<int>>pos_vec;
        //vector<int>pos_1 = { 0,0 };
        //vector<int>pos_2 = { 3,1 };

        //Solution01 solu(pos_vec);

        //vector<string>result = solu.compute(pos_1, pos_2);
        //for (auto&str:result)
        //{
        //    cout << str << endl;
        //}

        return 0;
	}
	{
        string num_str, exclu_str;
        cin >> num_str >> exclu_str;

        Solution03 solu(num_str, exclu_str);

        return 0;
	}
    //int target_i = 2;
    //aaa_password_"a12_45678"_timeout_100_""_
    int target_i;
    cin >> target_i;
    string input;
    cin >> input;
    Solution02 solu(input, target_i);

}

// 运行程序: Ctrl + F5 或调试 >“开始执行(不调试)”菜单
// 调试程序: F5 或调试 >“开始调试”菜单

// 入门使用技巧: 
//   1. 使用解决方案资源管理器窗口添加/管理文件
//   2. 使用团队资源管理器窗口连接到源代码管理
//   3. 使用输出窗口查看生成输出和其他消息
//   4. 使用错误列表窗口查看错误
//   5. 转到“项目”>“添加新项”以创建新的代码文件，或转到“项目”>“添加现有项”以将现有代码文件添加到项目
//   6. 将来，若要再次打开此项目，请转到“文件”>“打开”>“项目”并选择 .sln 文件
